#include "mkvmuxfilter.hpp"
#include "mkvstreamaudioac3.hpp"
#include <uuids.h>
#include <vfwmsgs.h>
#include <cassert>

namespace MkvMux
{

InpinAudio::InpinAudio(Filter* p) : Inpin(p, L"audio")
{
    AM_MEDIA_TYPE mt;
    
    mt.majortype = MEDIATYPE_Audio;
    mt.subtype = MEDIASUBTYPE_DOLBY_AC3;
    
    mt.bFixedSizeSamples = FALSE;
    mt.bTemporalCompression = FALSE;
    mt.lSampleSize = 0;
    mt.formattype = GUID_NULL;
    mt.pUnk = 0;
    mt.cbFormat = 0;
    mt.pbFormat = 0;
    
    m_preferred.Add(mt);
}


InpinAudio::~InpinAudio()
{
}





HRESULT InpinAudio::QueryAccept(const AM_MEDIA_TYPE* pmt)
{
    if (pmt == 0)
        return E_INVALIDARG;
    
    const AM_MEDIA_TYPE& mt = *pmt;

    if (mt.majortype != MEDIATYPE_Audio)
        return S_FALSE;
        
    if (mt.subtype != MEDIASUBTYPE_DOLBY_AC3)  //TODO: accept more audio subtypes
        return S_FALSE;
        
    //TODO: require format structure?  Require samplerate=48K?  etc
    
    return S_OK;  //TODO: anything else here?
}


HRESULT InpinAudio::GetAllocatorRequirements(ALLOCATOR_PROPERTIES* p)
{
    if (p == 0)
        return E_POINTER;
        
    ALLOCATOR_PROPERTIES& props = *p;
    
    props.cBuffers = 2;
    props.cbBuffer = 0;
    props.cbAlign = 0;
    props.cbPrefix = 0;
    
    return S_OK;
}



HRESULT InpinAudio::OnInit()
{
   assert(m_connection);
   assert(!m_connection_mt.Empty());
   
   const AM_MEDIA_TYPE& mt = m_connection_mt[0];
   assert(mt.majortype == MEDIATYPE_Audio);
   assert(mt.formattype == FORMAT_WaveFormatEx);
   
   const ULONG cb = mt.cbFormat;
   assert(cb >= sizeof(WAVEFORMATEX));

   const BYTE* const pb = mt.pbFormat;
   assert(pb);
   
   MkvContext& ctx = m_pFilter->m_mkv;

   //TODO: generalize this to other audio codec types
   MkvStreamAudioAc3* const pStream =
     new (std::nothrow) MkvStreamAudioAc3(ctx, pb, cb);
   assert(pStream);  //TODO
   
   //TODO: generalize this to accept multiple audio streams
   ctx.SetAudio(pStream);
   m_pStream = pStream;

   return S_OK;
}


void InpinAudio::OnFinal()
{
   MkvContext& ctx = m_pFilter->m_mkv;
   ctx.SetAudio(0);
}


HRESULT InpinAudio::OnReceiveConnection(
    IPin*,
    const AM_MEDIA_TYPE& mt)
{
    if (mt.majortype != MEDIATYPE_Audio)
        return VFW_E_TYPE_NOT_ACCEPTED;
        
    if (mt.subtype != MEDIASUBTYPE_DOLBY_AC3)  //TODO: accept more audio subtypes
        return VFW_E_TYPE_NOT_ACCEPTED;
        
    if (mt.formattype != FORMAT_WaveFormatEx)
        return VFW_E_TYPE_NOT_ACCEPTED;
    
    if (mt.cbFormat < sizeof(WAVEFORMATEX))
        return VFW_E_TYPE_NOT_ACCEPTED;
        
    if (mt.pbFormat == 0)
        return VFW_E_TYPE_NOT_ACCEPTED;

    const WAVEFORMATEX& wfx = (WAVEFORMATEX&)(*mt.pbFormat);
    wfx;    

    return S_OK;  //TODO: anything else here?
}


//HRESULT InpinAudio::OnReceive(IMediaSample* pSample)
//{
//    return m_pFilter->m_outpin.WriteAudio(pSample);
//}
//
//
//HRESULT InpinAudio::OnEndOfStream()
//{
//    return m_pFilter->m_outpin.WriteAudioEOS();
//}

HANDLE InpinAudio::GetOtherHandle() const
{
    const InpinVideo& iv = m_pFilter->m_inpin_video;    
    return iv.m_hSample;
}



} //end namespace MkvMux
